/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.draw2d.IFigure;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.Request;
import org.eclipse.uml2.uml.CombinedFragment;
import org.eclipse.uml2.uml.InteractionOperatorKind;
import org.eclipse.uml2.uml.UMLPackage;

import com.cea.papyrus.core.editor.ModelManager;
import com.cea.papyrus.core.helper.ModelerHelper;
import com.cea.papyrus.diagram.sequence.sedi.edit.manager.CombinedFragmentEditManager;
import com.cea.papyrus.diagram.sequence.sedi.edit.policy.CFLayoutPolicy;
import com.cea.papyrus.diagram.sequence.sedi.edit.policy.CombinedFragmentDirectEditPolicy;
import com.cea.papyrus.diagram.sequence.sedi.edit.policy.DeletionEditPolicy;
import com.cea.papyrus.diagram.sequence.sedi.edit.policy.GraphConnectionPolicy;
import com.cea.papyrus.diagram.sequence.sedi.figures.AnchoringFigure;
import com.cea.papyrus.diagram.sequence.sedi.figures.CombinedFragmentFigure;
import com.cea.papyrus.diagram.sequence.sedi.figures.ILabeledFigure;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;
import com.cea.papyrus.diagraminterchange2.di2.Property;

/**
 * Edit part for Combined Fragments.
 * 
 * @author Andreas Limyr
 * @author frankd@ifi.uio.no
 */
public class CFEditPart extends AnchoringEditPart<CombinedFragment> {

	public CFEditPart(GraphElement view, ModelManager modelManager) {
		super(view, modelManager);
	}

	@Override
	protected IFigure createFigure() {
		AnchoringFigure figure = new CombinedFragmentFigure();
		figure.setMessageAccess(this);
		return figure;
	}

	@Override
	protected void createEditPolicies() {
		super.createEditPolicies();

		// override the default DirectEditPolicy since CFs display the
		// operator, not the NamedElement name
		installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE,
				new CombinedFragmentDirectEditPolicy());

//		installEditPolicy(EditPolicy.COMPONENT_ROLE,
//				new SeDiSubpartEditPolicy());
//		installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE,
//				new SeDiNodeEditPolicy());
		
        // Manage connection between this element and others
		this.installEditPolicy(
				EditPolicy.GRAPHICAL_NODE_ROLE, 
				new GraphConnectionPolicy() );
        // Add edit policy to handle deletion requests (replace SeDiSubpartEditPolicy)
		installEditPolicy(
				EditPolicy.COMPONENT_ROLE,
		        new DeletionEditPolicy());
		
		installEditPolicy(EditPolicy.LAYOUT_ROLE, new CFLayoutPolicy());

		// super.refreshVisuals();
	}

	@Override
	protected void performDirectEdit(final Request request) {
		new CombinedFragmentEditManager(this, getCellEditorLocator()).show();
	}

	@Override
	protected void refreshVisualsLabel() {
		CombinedFragment cfragment = getUmlElement();
		InteractionOperatorKind op = cfragment.getInteractionOperator();
		ILabeledFigure figure = (ILabeledFigure) getFigure();
		figure.setLabel(op != null ? op.getName() : "<op>");
	}

	@SuppressWarnings("unchecked")
	@Override
	protected List getModelChildren() {
		ArrayList contained= new ArrayList();
			
		// if the presentation of the element is not shape we can display children, otherwise we can't
		if (getGraphNode().getSemanticModel() != null) {
			if ((getGraphNode().getSemanticModel().getPresentation() == null) ||
					!(getGraphNode().getSemanticModel().getPresentation().equals(ModelerHelper.IMAGE_STEREOTYPE_PRESENTATION))) {
				
				Iterator it=getGraphNode().getContained().iterator();
				while (it.hasNext()){
					GraphElement ge=(GraphElement)it.next();
					contained.add(ge);
				}
			}
		}
		return contained;
	}
	
//	@SuppressWarnings("unchecked")
//	@Override
//	protected List getModelChildren() {
//		final List childrenViews = new LinkedList();
//
//		final GraphNode cfragmentView = (GraphNode) getModel();
//		final CombinedFragment cfragment = ModelUtil
//				.<CombinedFragment> getSemantic(cfragmentView);
//		final Diagram diagram = LookForElement.getDiagram(cfragmentView);
//
//		// TODO The code below can go into a handler
//		diagram.eSetDeliver(false);
//		try {
//			final ModelSynchronizer synchronizer = new ModelSynchronizer(
//					diagram, this);
//
//			// Children of CombinedFragments are:
//			// InteractionOperand, InteractionConstraint
//			//
//			// We are only interested in operands because we want to display
//			// separators *between*. We do this by associating a SeparatorView
//			// with every operand except the first. A separator therefore
//			// separates its associated operand and the operand /before/ it.
//
//			for (GraphElement element : ModelUtil.getContents(diagram)) {
//				if (neIsInstance(element, InteractionOperand.class)) {
//					final GraphEdge separator = (GraphEdge) element;
//					final InteractionOperand op = ModelUtil
//							.<InteractionOperand> getSemantic(separator);
//					if (op.getOwner() == null // garbage collection
//							|| op.getOwner() == getUmlElement())
//						synchronizer.registerElement(element);
//				} else if (neIsInstance(element, InteractionConstraint.class)) {
//					GraphElement ge = (GraphElement) element;
//					InteractionConstraint guard = ModelUtil
//							.<InteractionConstraint> getSemantic(ge);
//					if (guard.getOwner() == null // garbage collection
//							|| guard.getOwner().getOwner() == getUmlElement())
//						synchronizer.registerElement(element);
//				}
//			}
//
//			final List<InteractionOperand> operandList = getOperands(cfragment);
//			boolean doSynchronize = false; // Skip the first operand
//			for (InteractionOperand operand : operandList) {
//				if (operand.getGuard() != null) {
//					GraphElement ge = synchronizer.synchronizeElement(operand
//							.getGuard());
//					if (ge != null) {
//						childrenViews.add(ge);
//					}
//				}
//
//				if (doSynchronize)
//					synchronizer.synchronizeElement(operand);
//				// but do not add as child
//				else
//					doSynchronize = true;
//			}
//
//			synchronizer.cleanup();
//		} finally {
//			diagram.eSetDeliver(true);
//		}
//
//		return childrenViews;
//	}

	@SuppressWarnings("unchecked")
	@Override
	protected void umlModelChanged(Notification evt) {
		switch (evt.getFeatureID(UMLPackage.class)) {
		case UMLPackage.COMBINED_FRAGMENT__INTERACTION_OPERATOR:
			refreshVisualsLabel();
			break;

		case UMLPackage.COMBINED_FRAGMENT__OPERAND:
			switch (evt.getEventType()) {
			case Notification.ADD:
			case Notification.ADD_MANY:
//				maybeAddUmlAdapter(evt.getNewValue());
//				refreshChildren();
//				break;
			case Notification.REMOVE:
			case Notification.REMOVE_MANY:
//				maybeRemoveUmlAdapter(evt.getOldValue());
//				refreshChildren();
//				break;
			case Notification.MOVE:
				refreshChildren();
			}
			break;

		case UMLPackage.INTERACTION_OPERAND__GUARD:
//			maybeRemoveUmlAdapter(evt.getOldValue());
//			maybeAddUmlAdapter(evt.getNewValue());
//			refreshChildren();
//			break;

		default:
			super.umlModelChanged(evt);
		}
	}

	// --- Activation ---

	/**
	 * Identifies the objects that this EditPart has installed UML adapters on.
	 * It is a Helper list - not required, but enables us to avoid recursive
	 * search (and additional programming mistakes) during deactivation.
	 */
	private List<EObject> umlAdaptersOn = new LinkedList<EObject>();

	// TODO refactor - this code is to a large degree common for
	// frameEP, diagramEP and cfEP

	@Override
	public void activate() {

			if (this.isActive()) {
				return;
			}
			super.activate();
			// Start listening for changes in the model
			((Notifier)this.getModel()).eAdapters().add(graphElementListener);
			
			Iterator<Property> propertiesIterator= ((GraphNode) this.getModel()).getProperty().iterator();
			while(propertiesIterator.hasNext()){
				((Notifier)propertiesIterator.next()).eAdapters().add(graphElementListener);
			}
//			// Super attaches listener to the CF.
//			// In addition, we want adapters on all interaction operands
//			// and their guards
//
//			maybeAddUmlAdapter(getUmlElement().getOperands());
	}

	@Override
	public void deactivate() {
		if (!this.isActive()) {
			return;
		}

		// Stop listening for changes in the model
		((Notifier)this.getModel()).eAdapters().remove(graphElementListener);
		
		Iterator<Property> propertiesIterator= ((GraphNode) this.getModel()).getProperty().iterator();
		while(propertiesIterator.hasNext()){
			((Notifier) propertiesIterator.next()).eAdapters().remove(graphElementListener);
		}
		
		super.deactivate();
		
//		if (isActive()) {
//			for (EObject o : umlAdaptersOn)
//				o.eAdapters().remove(umlAdapter);
//			umlAdaptersOn.clear();
//
//			super.deactivate();
//		}
	}

//	private void maybeAddUmlAdapter(Object o) {
//		if (o instanceof InteractionOperand) {
//			addUmlAdapter((EObject) o);
//			maybeAddUmlAdapter(((InteractionOperand) o).getGuard());
//		} else if (o instanceof InteractionConstraint) {
//			addUmlAdapter((EObject) o);
//		} else if (o instanceof List) {
//			for (Object child : (List<?>) o)
//				maybeAddUmlAdapter(child);
//		}
//	}
//
//	private void maybeRemoveUmlAdapter(Object o) {
//		if (o instanceof InteractionOperand) {
//			removeUmlAdapter((EObject) o);
//			maybeRemoveUmlAdapter(((InteractionOperand) o).getGuard());
//		} else if (o instanceof InteractionConstraint) {
//			removeUmlAdapter((EObject) o);
//		} else if (o instanceof List) {
//			for (Object child : (List<?>) o)
//				maybeRemoveUmlAdapter(child);
//		}
//	}
//
//	@SuppressWarnings("unchecked")
//	private void addUmlAdapter(EObject o) {
//		o.eAdapters().add(umlAdapter);
//		umlAdaptersOn.add(o);
//	}
//
//	@SuppressWarnings("unchecked")
//	private void removeUmlAdapter(EObject o) {
//		o.eAdapters().remove(umlAdapter);
//		umlAdaptersOn.remove(o);
//	}
}
